﻿// ReSharper disable InconsistentNaming

using System;
using System.Collections.Generic;


namespace Gp.Scripts.Core.Skill
{
    public class DisableReason
    {
        private readonly LinkedList<DisableReasonNode> _ls;

        public DisableReason(DS_Reason rs, Func<bool> judge)
        {
            _ls = new LinkedList<DisableReasonNode>();
            _ls.AddLast(new DisableReasonNode(rs, judge));
        }

        public static DisableReason Build(DS_Reason rs, Func<bool> judge = null)
        {
            return new DisableReason(rs, judge);
        }

        public static DisableReason True()
        {
            return new DisableReason(DS_Reason.True, () => true);
        }

        public DisableReason And(DS_Reason rs, Func<bool> judge)
        {
            _ls.AddLast(new DisableReasonNode(rs, judge));
            return this;
        }

        public DisableReason And(DisableReason rs)
        {
            foreach (var node in rs._ls)
            {
                _ls.AddLast(node);
            }

            return this;
        }


        public bool Result(out DS_Reason rs)
        {
            rs = DS_Reason.EMPTY;
            foreach (var node in _ls)
            {
                rs = node.Reason;
                var judge = node.res();
                if (!judge) return false;
            }

            return true;
        }

        public bool Result()
        {
            return Result(out _);
        }

        // 重载bool运算符
        public static bool operator true(DisableReason obj)
        {
            return obj.Result();
        }

        public static bool operator false(DisableReason obj)
        {
            return !obj.Result();
        }

        public static bool operator !(DisableReason obj)
        {
            return !obj.Result();
        }


        private struct DisableReasonNode
        {
            public DS_Reason Reason;
            public Func<bool> res;


            public DisableReasonNode(DS_Reason reason, Func<bool> res)
            {
                Reason   = reason;
                this.res = res;
            }
        }
    }

    public enum DS_Reason
    {
        /// <summary>
        /// 空信息
        /// </summary>
        EMPTY,

        True,


        /// <summary>
        /// 无使用次数
        /// </summary>
        UsedChance,

        /// <summary>
        /// 对应资源不足
        /// </summary>
        COST_NOT_ENOUGH,


        /// <summary>
        /// 需要近战武器
        /// </summary>
        NEED_MELEE_WEAPON,


        /// <summary>
        /// 无法移动
        /// </summary>
        MoveBlock,

        /// <summary>
        /// 没有足够的弹药
        /// </summary>
        NoEnoughAmmo,

        /// 技能目标非法 
        InvalidTarget,
    }

    public static class DsReasonExtend
    {
        public static string Text(this DS_Reason reason)
        {
            return reason switch
            {
                DS_Reason.EMPTY             => "无法使用",
                DS_Reason.True              => "TRUE",
                DS_Reason.UsedChance        => "无使用次数",
                DS_Reason.COST_NOT_ENOUGH   => "所需资源不足",
                DS_Reason.NEED_MELEE_WEAPON => "需要近战武器",
                DS_Reason.MoveBlock         => "单位被禁锢",
                DS_Reason.NoEnoughAmmo      => "武器没有足够弹药",
                DS_Reason.InvalidTarget     => "目标无效",
                _                           => throw new ArgumentOutOfRangeException(nameof(reason), reason, null)
            };
        }


        public static DisableReason QAdd(this DisableReason chain, DS_Reason reason, SkillEntity skill)
        {
            chain.And(reason, reason.Judge(skill));
            return chain;
        }


        public static Func<bool> Judge(this DS_Reason reason, SkillEntity skill)
        {
            return reason switch
            {
                DS_Reason.EMPTY                   => () => false,
                DS_Reason.True                   => () => true,
                DS_Reason.COST_NOT_ENOUGH               => () => false,
                DS_Reason.NEED_MELEE_WEAPON        => () => false,
                DS_Reason.MoveBlock              => () => false,
                DS_Reason.NoEnoughAmmo           => () => false,
                _                                => () => true,
            };
        }


        // private static bool UsedChanceJudge(SkillEntity skill) {
        //     return !skill.LimitedUsedChance || skill.UsedChance > 0;
        // }

        private static bool MeleePosJudge(SkillEntity skill)
        {
            return true;
        }

        private static bool FirstPosJudge(SkillEntity skill)
        {
            return true;
        }
    }
}